package classload;

import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CustomClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //初始化自定义类加载器，会先初始化父类ClassLoader，其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        CustomClassLoader customClassLoader = new CustomClassLoader("G:/jvmtest");
        //G盘创建 jvmtest/classload 目录，将User类的复制类User1.class丢入该目录
        // class文件中package的值一定要与磁盘目录一致
        Class<?> userClass = customClassLoader.loadClass("classload.User");
        Object o = userClass.newInstance();
        Method sout = userClass.getDeclaredMethod("sout", null);
        sout.invoke(o, null);
        System.out.println(userClass.getClassLoader().getClass().getName());
    }


    static class CustomClassLoader extends ClassLoader {
        private String classPath;

        public CustomClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadClassByte(String name) throws Exception {
            name = name.replaceAll("\\.", "/");
            FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
            int available = fileInputStream.available();
            byte[] bytes = new byte[available];
            fileInputStream.read(bytes);
            fileInputStream.close();
            return bytes;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadClassByte(name);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                        long t1 = System.nanoTime();
                        // 非业务类还是由双亲委托完成，不然报错：G:\jvmtest\java\lang\Object.class (系统找不到指定的路径。)
                        if (!name.startsWith("classload")) {
                            c = this.getParent().loadClass(name);
                        } else {
                            c = findClass(name);
                        }

                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }
}
